  

/*  hartcmd.c
    For use with tm40.c
    Stephen D. Anderson --- July 30, 1994

    Function sends a long-frame HART command and gets response if any.
    Updates status display.  Checks for key event each time through
    comm attempt loop.

    ON ENTRY:
        *c_data is pointer to the command data.
        c_numb is the number of command bytes to be sent.
        *r_data is pointer to the response data.
        r_numb is the maximum number of response bytes to be
            written into r_data.
        addr is a pointer to numb preambles and address to use.
        cmd is the command to send.

    ON EXIT:
        if successful, the lower byte of the returned integer is 0
        and upper byte is number of received bytes.
        if not successful the lower byte of returned integer is 1.
        if key event has occurred, returned integer is 2.
        global variables status1, status2 are written.

    REVISION LOG:

    Version 4.3:
    1.  Changed to mask out the burst bit in a received message
        before checking address.

    2.  July 18, 1995:  fixed so that r_d and c_d pointers are
        initialized at proper points.
*/

#include "tm40.h"

int hartcmd(byte *c_data, byte c_numb, byte *r_data, byte r_numb,
    byte *addr, byte cmd)


{
    extern byte send[], receive[], receive_err[];
    extern byte status1, status2;
    extern byte status_wind,drb,rec_byte_wind;

    extern byte Checksum(byte *, byte);
    extern byte Checkpar(byte *, byte);
    extern int send_rec(byte);

    byte i,j,k,j1;
    byte n_tries;
    byte cs_start;
    byte *r_d,*c_d;
    byte *r, *re, *s, *a;
    byte start_delim[3] = {0xff, 0xff, 0x86};
    byte numb_pre;
    byte byte_count;
    int rec_bytes;
    byte disp_bytes[200],dump[5];
    byte xmit_bytes;
    byte start_delim_found;

    /*  point to address. */
    a = addr;

    /*  clear the status bytes in case we don't get to write them later. */
    status1 = 0; status2 = 0;

    /*  build the xmit message. */
    numb_pre = *a++;    /*  build preamble. */
    if ((numb_pre < 5) || (numb_pre > 20)) numb_pre = 20;
    for (i=0; i<numb_pre; ++i) send[i]=0xff;
    send[i++]=0x82;     /*  start delimiter. */
    s=&send[i];         /* point to start of message. */
    send[i++] = (0x80 | *a++);  /* 1st address byte. */
    for(j=1; j<=4; ++j) send[i++] = *a++;   /*  next 4 addr bytes. */
    send[i++] = cmd;      /* command. */
    send[i++] = c_numb;      /* byte count. */
    for(j=1, c_d = c_data; j<=c_numb; ++j) send[i++] = *c_d++;
    send[i] = Checksum((send+numb_pre), i-numb_pre);    /* checksum byte. */
    xmit_bytes = i+1;

    /*  try sending it up to 10 times. */
    for(n_tries=1; n_tries<=10; ++n_tries)
    {
        if (KeyEvent()) return(2);

        /*  indicate which retry. */
        WVprtf(status_wind,0,36,BLACK|_GREEN,"%d ",n_tries);

        /*  do next try.  continue if error. */
        rec_bytes = send_rec(xmit_bytes);
        /* rec_bytes = 1; */ /*  insert for test.  */
        if ((rec_bytes & 0xff) == 1) continue;
        if ((rec_bytes & 0xff) == 3) continue;

        /*  else get number of received bytes. */
        k = rec_bytes/256;

        /*  if drb set, then display the received bytes. */
        if (drb)
        {
            r = receive; disp_bytes[0] = NULL;
            for (i=0; i<k; ++i) 
            {
                strcat(disp_bytes, itoa(*r++, dump, 16));
                strcat(disp_bytes, " ");
            }
            WVclear(rec_byte_wind);
            WVputs(rec_byte_wind, disp_bytes);
            delay(1000);
        }

        /* find start delimiter. */
        r=receive;
        for (j=1, start_delim_found=0; j <= k; ++j)
        {
            if ((strncmp(r++, start_delim, 3)) == 0) 
            {
                ++start_delim_found;
                break;
            }
        }
        /*  start_delim_found = 0;  */ /*  test statement.  */
        if (start_delim_found == 0) continue;

        /* go to start delim. */
        j += 2; ++r;
        /*  j = k+1;    */  /*  test statement.  */
        if (j > k) continue;    /*  try again if too few bytes. */

        cs_start = j;   /* mark position. */

        ++j; ++r;       /* advance to address. */

        /*  j = 0;  */      /*  test statement.  */
        if ((k-j+1) < 6) continue;  /*  try again if too few. */

        /*  does 1st byte of address with stripped burst bit match?  */
        /*  *s = 0; */  /*  test statement.  */
        if ( (*r & 0xbf) != *s) continue;

        ++j; ++r;   /*  advance to remainder of address.  */

        /*  *r = 0xff;  */  /*  test statement.  */
        /*  do remainder of address and command match?  */
        if ((strncmp(r, s+1, 5)) != 0) continue;

        j += 5; r += 5;  /* skip to byte count. */
        if (j > k) continue;    /*  too few? */
        byte_count = *r-2;

        /*  byte_count = r_numb + 1;    */  /*  test statement.  */
        if (byte_count > r_numb) continue;  /*  too many?  */

        ++j;  ++r;  /*  skip to status. */
        status1 = *r++; ++j;     /*  save it.  */
        status2 = *r++; ++j;

        /*  save data. */
        for (j1=1, r_d = r_data; j1<=byte_count; ++j1) *r_d++ = *r++;

        /*  do error checking.  */
        r = &receive[cs_start-1];
    /*  *r = 0xaa;  */  /*  test statement.  */
        re = &receive_err[cs_start-1];
    /*  *re = 1;    */  /*  test statement.  */
        j += byte_count;

        if ((Checksum(r, j-cs_start+1)) != 0) continue;

        if ((Checkpar(re, j-cs_start+1)) == 0)
            return(256*byte_count);
    }
    return(1);
}

